package cn.iocoder.yudao.module.erp.service.finance.bankstatementitem;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.finance.bankstatementitem.vo.AllotAmountVO;
import cn.iocoder.yudao.module.erp.controller.admin.finance.bankstatementitem.vo.BankStatementItemPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.finance.bankstatementitem.vo.BankStatementItemSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.dp.DpDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.bankstatement.BankStatementDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.bankstatementitem.BankStatementItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.supplierfleet.SupplierFleetDO;
import cn.iocoder.yudao.module.erp.dal.mysql.dp.DpMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.finance.bankstatement.BankStatementMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.finance.bankstatementitem.BankStatementItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.supplierfleet.SupplierFleetMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.LocalDateTime;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;

/**
 * 银行流水明细 Service 实现类
 * @author 天使管理员
 */
@Service
@Validated
public class BankStatementItemServiceImpl implements BankStatementItemService {

    @Resource
    private BankStatementItemMapper bankStatementItemMapper;
    @Resource
    private BankStatementMapper bankStatementMapper;
    @Resource
    private SupplierFleetMapper supplierFleetMapper;
    @Resource
    private DpMapper dpMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createBankStatementItem(BankStatementItemSaveReqVO createReqVO) {
        // 插入
        BankStatementItemDO bankStatementItem = BeanUtils.toBean(createReqVO, BankStatementItemDO.class);
        Gson gs = new Gson();
        bankStatementItem.setInfo(gs.toJson(createReqVO));
        bankStatementItemMapper.insert(bankStatementItem);

        //更新银行流水erp_bank_statement的daily_balance
        BankStatementDO bankStatementDO = new BankStatementDO();
        String cardId = createReqVO.getCardId();
        bankStatementDO.setId(cardId);
        bankStatementDO.setDailyBalance(createReqVO.getBalance());
        BankStatementDO totalDO = bankStatementMapper.getBankAmountTotalByCardId(cardId);
        bankStatementDO.setDayPayment(totalDO.getDayPaymentSum());
        bankStatementDO.setDailyExpenses(totalDO.getDailyExpensesSum());
        bankStatementDO.setRecordDate(createReqVO.getRecordDate());
        bankStatementMapper.updateById(bankStatementDO);
        //发货人不为空插入数据至财务数据
        if(StringUtils.isNotEmpty(createReqVO.getShipper())) {
            Double advanceAmount = createReqVO.getAdvanceAmount() == null ? 0 : createReqVO.getAdvanceAmount();
            if (advanceAmount > 0){
                DpDO dpDO = new DpDO();
                dpDO.setNo(createReqVO.getRemark());
                dpDO.setId(generateId()); // 设置唯一 ID
                dpDO.setChooseDate(createReqVO.getRecordDate());
                dpDO.setShipper(createReqVO.getShipper());
                dpDO.setStatus(3);
                dpDO.setInName(createReqVO.getNote());
                dpDO.setTotalAmount(advanceAmount);
                dpDO.setDebtTotal(advanceAmount);
                dpMapper.insert(dpDO);
            }
            //自动分配前的逻辑
//            if (StringUtils.isNotEmpty(createReqVO.getNo())){
//                DpDO dpDO = new DpDO();
//                dpDO.setNo(createReqVO.getNo());
//                Double isWriteOff = createReqVO.getIsWriteOff() == null ? 0 : createReqVO.getIsWriteOff();
//                dpDO.setIsWriteOff(isWriteOff);
//                dpDO.setNotWriteOff(createReqVO.getWriteExpenses() - isWriteOff);
//                Double isPoint = createReqVO.getIsPoint() == null ? 0 : createReqVO.getIsPoint();
//                dpDO.setIsPoint(isPoint);
//                dpDO.setNotPoint(createReqVO.getCustomerRebate() - isPoint);
//                dpDO.setReceivedFare(createReqVO.getDepositAmount());
//                dpMapper.updateByNo(dpDO);
//            }
//        }
            //自动分配后的逻辑
            List<AllotAmountVO> allotAmountList = createReqVO.getAllotAmountList();
            if (allotAmountList != null && allotAmountList.size() > 0){
                List<DpDO> dpList = new ArrayList<>();
                for (AllotAmountVO amountVO : allotAmountList) {
                    DpDO dpDO = new DpDO();
                    dpDO.setId(amountVO.getId());
                    dpDO.setNo(amountVO.getNo());
                    Double isWriteOff = amountVO.getIsWriteOff() == null ? 0 : amountVO.getIsWriteOff();
                    dpDO.setIsWriteOff(isWriteOff);
                    dpDO.setNotWriteOff(amountVO.getNotWriteOff() - isWriteOff);
                    Double isPoint = amountVO.getIsPoint() == null ? 0 : amountVO.getIsPoint();
                    dpDO.setIsPoint(isPoint);
                    dpDO.setNotPoint(amountVO.getNotPoint() - isPoint);
                    dpDO.setReceivedFare(amountVO.getAllotDepositAmount());
                    dpList.add(dpDO);
                }
                dpMapper.batchUpdateById(dpList);
            }
        }
        if(createReqVO.getSupplier() != null) {
            //插入一条数据到供应商车队
            SupplierFleetDO supplierFleetDO = new SupplierFleetDO();
            supplierFleetDO.setType(1);
            supplierFleetDO.setCategory(createReqVO.getCategory());
            supplierFleetDO.setName(createReqVO.getSupplier());
            supplierFleetDO.setFleet(createReqVO.getFleet());
            supplierFleetDO.setPaidAmount(createReqVO.getHsPayAmount());
            supplierFleetDO.setTotalAmount(createReqVO.getHsIncomeAmount());
            supplierFleetDO.setCurrencyType(createReqVO.getCurrencyType());
            // 处理 LocalDate 和 LocalDateTime
            Gson gson = new GsonBuilder()
                    .registerTypeAdapter(LocalDate.class, (JsonSerializer<LocalDate>) (localDate, type, jsonSerializationContext) ->
                            new JsonPrimitive(localDate.format(DateTimeFormatter.ISO_LOCAL_DATE))
                    )
                    .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (localDateTime, type, jsonSerializationContext) ->
                            new JsonPrimitive(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    )
                    .create();
            String info = gson.toJson(createReqVO);
            supplierFleetDO.setInfo(info);
            supplierFleetDO.setIsShow(createReqVO.getIsShow());
            supplierFleetMapper.insert(supplierFleetDO);
        }
        if(createReqVO.getSupplier()==""||createReqVO.getSupplier()==null){

            String xx=bankStatementItem.getCardId();
            bankStatementItem.setCardId(createReqVO.getFleet());
            bankStatementItem.setFleet(xx);

            BankStatementDO x=bankStatementMapper.selectById(createReqVO.getFleet());
            if(createReqVO.getPayAmount()!=0){
                bankStatementItem.setPayAmount(0.0);
                bankStatementItem.setIncomeAmount(createReqVO.getHsIncomeAmount());
                x.setDailyBalance(x.getDailyBalance() + createReqVO.getHsIncomeAmount());
            }else if(createReqVO.getIncomeAmount()!=0){
                bankStatementItem.setIncomeAmount(0.0);
                bankStatementItem.setPayAmount(createReqVO.getHsPayAmount());
                x.setDailyBalance(x.getDailyBalance() - createReqVO.getHsPayAmount());
            }
            bankStatementItem.setBalance(x.getDailyBalance());
            bankStatementItem.setId(null);
            if (bankStatementMapper.updateById(x)>0) {
                bankStatementItemMapper.insert(bankStatementItem);
            }
        }
        // 返回
        return bankStatementItem.getId();
    }

    public static String generateId() {
        return new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
    }

    @Override
    public void updateBankStatementItem(BankStatementItemSaveReqVO updateReqVO) {
        // 校验存在
        validateBankStatementItemExists(updateReqVO.getId());
        // 更新
        BankStatementItemDO updateObj = BeanUtils.toBean(updateReqVO, BankStatementItemDO.class);
        bankStatementItemMapper.updateById(updateObj);
    }

    @Override
    public void deleteBankStatementItem(Long id) {
        // 校验存在
        validateBankStatementItemExists(id);
        // 删除
        bankStatementItemMapper.deleteById(id);
    }

    private void validateBankStatementItemExists(Long id) {
        if (bankStatementItemMapper.selectById(id) == null) {
            throw exception(BANK_STATEMENT_ITEM_NOT_EXISTS);
        }
    }

    @Override
    public BankStatementItemDO getBankStatementItem(Long id) {
        return bankStatementItemMapper.selectById(id);
    }

    @Override
    public PageResult<BankStatementItemDO> getBankStatementItemPage(BankStatementItemPageReqVO pageReqVO) {
        return bankStatementItemMapper.selectPage(pageReqVO);
    }

    @Override
    public BankStatementItemDO getBankItemAmountTotal(BankStatementItemPageReqVO pageReqVO) {
        // 执行查询
        List<BankStatementItemDO> list = bankStatementItemMapper.selectPage(pageReqVO).getList();
        // 计算字段总和
        double incomeAmountSum = list.stream()
                .mapToDouble(BankStatementItemDO::getIncomeAmount) // 转换为 DoubleStream
                .sum(); // 计算总和
        double payAmountSum = list.stream()
                .mapToDouble(BankStatementItemDO::getPayAmount)
                .sum();
        Double balanceSum = 0.0;
        if (list != null && list.size() > 0) {
            balanceSum = list.get(0).getBalance();
        }
        BankStatementItemDO bankStatementItemDO = new BankStatementItemDO();
        bankStatementItemDO.setIncomeAmountSum(incomeAmountSum);
        bankStatementItemDO.setPayAmountSum(payAmountSum);
        bankStatementItemDO.setBalanceSum(balanceSum);
        return bankStatementItemDO;
    }

}